//
// Created by Martin on 2022/10/3.
//
#include <iostream>
using namespace std;

template<typename T>
struct type_descriptor
{
    static std::string value;
    operator const char* ()
    {
        return value.c_str();
    }

    std::string& operator()()
    {
        return value;
    }
};

// static 成员初始化在类外

template<typename T>
std::string type_descriptor<T>::value = "unknown type";

template<>
std::string type_descriptor<char>::value = "char";

template<>
std::string type_descriptor<short>::value = "short";

template<>
std::string type_descriptor<int>::value = "int";

template<>
std::string type_descriptor<long>::value = "long";

template<>
std::string type_descriptor<float>::value = "float";

template<>
std::string type_descriptor<double>::value = "double";

// 偏特化T const
template<typename T>
struct type_descriptor<T const>
{
    operator const char* ()
    {
        static std::string value = static_cast<const char *>(type_descriptor<T>());
        value += " const";
        return value.c_str();
    }
};

// 偏特化T volatile
template<typename T>
struct type_descriptor<T volatile>
{
    operator const char* ()
    {
        static std::string value = static_cast<const char *>(type_descriptor<T>());
        value += " volatile";
        return value.c_str();
    }
};

// 偏特化T*
template<typename T>
struct type_descriptor<T*>
{
    operator const char* ()
    {
        static std::string value = "pointer to ";
        value += static_cast<const char *>(type_descriptor<T>());
        return value.c_str();
    }
};

// 偏特化T&
template<typename T>
struct type_descriptor<T&>
{
    operator const char* ()
    {
        static std::string value = " reference to ";
        value += static_cast<const char *>(type_descriptor<T>());
        return value.c_str();
    }
};

// 偏特化T[]]
template<typename T>
struct type_descriptor<T[]>
{
    operator const char* ()
    {
        static std::string value = " array of ";
        value += static_cast<const char *>(type_descriptor<T>());
        return value.c_str();
    }
};

// 偏特化T(*)()
template<typename T>
struct type_descriptor<T(*)()>
{
    operator const char* ()
    {
        static std::string value = "pointer to function returning ";
        value += static_cast<const char *>(type_descriptor<T>());
        return value.c_str();
    }
};

//// 偏特化T*(Arg1) 指针函数, 返回值是指针的函数
//template<typename T, typename Arg1>
//struct type_descriptor<T*(Arg1)>
//{
//    operator const char* ()
//    {
//        static std::string value = "this is a pointer function with ";
//        value += static_cast<const char *>(type_descriptor<Arg1>());
//        value += " and it pointer to function returning ";
//        value += static_cast<const char *>(type_descriptor<T>());
//        return value.c_str();
//    }
//};

// 偏特化T(*)(Arg1)
template<typename T, typename Arg1>
struct type_descriptor<T(*)(Arg1)>
{
    operator const char* ()
    {
        std::cout << typeid(T).name() << "\n";
        static std::string value = "pointer to function with ";
        value += static_cast<const char *>(type_descriptor<Arg1>());
        value += " returning ";
        value += static_cast<const char *>(type_descriptor<T>());

        std::cout << typeid(T).name() << "\n";
        return value.c_str();
    }
};

// 偏特化T*(Arg1) 指针函数, 返回值是指针的函数
template<typename T, typename Arg1>
struct type_descriptor<T(*(Arg1))()>
{
    operator const char *() {
        static std::string ret = "this is a pointer function with ";
        ret += type_descriptor<Arg1>();
        ret += " and it pointer to function returning ";
        ret += type_descriptor<T>();

        return ret.c_str();
    }
};

template<typename T, typename Arg1, typename Arg2>
struct type_descriptor<T(*(Arg1))(Arg2)>
{
    operator const char *() {
        std::cout << typeid(T).name() << "\n";

        static std::string ret = "this is a pointer function with ";
        ret += type_descriptor<Arg1>();
        ret += " and it pointer to function with ";
        ret += type_descriptor<Arg2>();
        ret += " returning ";
        ret += type_descriptor<T>();

        std::cout << typeid(T).name() << "\n";
        return ret.c_str();
    }
};

static void test_type_descriptor()
{
    std::cout << type_descriptor<int>() << std::endl;
    typedef int(*FuncInt)(char*);
    typedef int(*FuncPoint[10])(char*);
    std::cout << type_descriptor<FuncInt>() << std::endl;
    std::cout << type_descriptor<FuncPoint>() << std::endl;
    std::cout << type_descriptor<const char*(*(int&))(const float *&)>() << std::endl;
}

int main()
{
    test_type_descriptor();
    return 0;
}